#include "RecordingThread.h"
extern "C"
{
#include <libavdevice/avdevice.h>
#include <libavutil/avutil.h>
#include <libavcodec/avcodec.h>
#include <libswresample/swresample.h>
#include <libavutil/audio_fifo.h>
}
#include <QFile>
#include <iostream>

CRecordingThread::CRecordingThread(QObject* parent)
	: QThread(parent)
	, m_pFmtCtx(nullptr)
	, m_pFile(nullptr)
	, m_bIsRecoring(false)
{
}

void CRecordingThread::setRecordStatus(bool bIsRecoring)
{
	m_bIsRecoring = bIsRecoring;
}

void CRecordingThread::setFormatContext(AVFormatContext* pFmtCtx)
{
	m_pFmtCtx = pFmtCtx;
}

void CRecordingThread::setFile(QFile* pFile)
{
	m_pFile = pFile;
}

void CRecordingThread::run()
{
	if (m_pFmtCtx == nullptr)
	{
		return;
	}
	if (m_pFile == nullptr)
	{
		return;
	}

    AVCodecContext* pCodecCtx = openCodec();
    AVFrame* pFrame = av_frame_alloc();
    if (!pFrame)
    {
        return;
    }
    pFrame->nb_samples = pCodecCtx->frame_size;
    pFrame->format = pCodecCtx->sample_fmt;
    pFrame->channel_layout = pCodecCtx->channel_layout;
    pFrame->channels = pCodecCtx->channels;
    av_frame_get_buffer(pFrame, 0);
    if(!(pFrame->data[0]))
    {
        return;
    }

    AVPacket pkt;
    av_init_packet(&pkt);

    AVPacket aacPkt;
    av_init_packet(&aacPkt);

    uint8_t* tmpData = new uint8_t[pFrame->linesize[0]]{0};
    int size = 0;

	while ((av_read_frame(m_pFmtCtx, &pkt) == 0) && m_bIsRecoring)
    {
        if (size < pFrame->linesize[0])
        {
            memcpy(tmpData + size, pkt.data, pkt.size);
            size += pkt.size;
        }
        if (size < pFrame->linesize[0])
        {
            continue;
        }
        memcpy(pFrame->data[0], tmpData, pFrame->linesize[0]);
        size = 0;
        int res = avcodec_send_frame(pCodecCtx, pFrame);
        while (res >= 0)
        {
            res = avcodec_receive_packet(pCodecCtx, &aacPkt);
            if ((res == AVERROR(EAGAIN)) || (res == AVERROR_EOF))
            {
                break;
            }
            if (res < 0)
            {
                av_packet_unref(&pkt);
                return;
            }
            if (aacPkt.size > 0)
            {
                QByteArray ba((const char*)aacPkt.data, aacPkt.size);
                m_pFile->write(ba);
                av_packet_unref(&aacPkt);
            }
        }
		av_packet_unref(&pkt);
	}
    delete[] tmpData;
}

AVCodecContext* CRecordingThread::openCodec()
{
    AVCodec* pCodec = avcodec_find_encoder_by_name("libfdk_aac");
	AVCodecContext* pCodecCtx = avcodec_alloc_context3(pCodec);
    pCodecCtx->sample_fmt = *pCodec->sample_fmts;
	pCodecCtx->channel_layout = AV_CH_LAYOUT_STEREO;
	pCodecCtx->sample_rate = 48000;
	pCodecCtx->channels = 2;
	pCodecCtx->bit_rate = 0;
	// bit_rate设置为0，profile才有效
    pCodecCtx->profile = FF_PROFILE_AAC_LOW;
	int res = avcodec_open2(pCodecCtx, pCodec, nullptr);
	if (res < 0)
	{
		return nullptr;
	}
	return pCodecCtx;
}

